using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;

namespace PBR
{
    /// <summary>
    /// Stores a heirarchy of blurred color and edge images
    /// </summary>
    public class Tier
    {
        // Blur data
        private float smallGamma = 1.4f;
        private float mediumGamma = 2.0f;
        private float largeGamma = 2.5f;
        private float xLargeGamma = 3.0f;

        private int smallSize = 5;
        private int mediumSize = 10;
        private int largeSize = 15;
        private int xLargeSize = 21;

        // Canny data
        private byte lowThreshold = 25;
        private byte highThreshold = 50;
        private double sigma = 1.4f;

        private const int numImages = 5;

        public List<BitmapUnsafe> ColorImages;
        public List<BitmapUnsafe> EdgesImages;

        /// <summary>
        /// Constructor for Tier
        /// </summary>
        /// <param name="scene">scene.Painting.ActiveLayer.ColorImage and scene.Painting.ActiveLayer.SegmentsImage must be initialized</param>
        public Tier(Bitmap colorImage, Bitmap segmentsImage)
        {
            if (segmentsImage == null || colorImage == null)
            {
                throw new ArgumentException("segmentsImage == null || colorImage == null");
            }

            BitmapUnsafe workingImage;

            ColorImages = new List<BitmapUnsafe>(numImages);
            EdgesImages = new List<BitmapUnsafe>(numImages);

            // Init filters
            AForge.Imaging.Filters.GaussianBlur gaussianBlur = new AForge.Imaging.Filters.GaussianBlur(smallGamma, smallSize);
            AForge.Imaging.Filters.CannyEdgeDetector cannyEdgeDetector = new AForge.Imaging.Filters.CannyEdgeDetector(lowThreshold, highThreshold, sigma);
            AForge.Imaging.Filters.GrayscaleBT709 grayscaleFilter = new AForge.Imaging.Filters.GrayscaleBT709();
            PBR.Filters.Composite compositeFilter = new PBR.Filters.Composite();
            PBR.Filters.AlphaMatteFromColor alphaMatteFromColorFilter = new PBR.Filters.AlphaMatteFromColor();
            AForge.Imaging.Filters.Erosion erosionFilter = new AForge.Imaging.Filters.Erosion();
            PBR.Filters.Threshold thresholdFilter = new PBR.Filters.Threshold(128);

            // Generate edges outline from segments image
            // this is overlayed onto the generated edges image
            Bitmap overlayImage = new Bitmap(segmentsImage);
            //erosionFilter.ApplyInPlace(overlayImage);
            //overlayImage = thresholdFilter.Apply(overlayImage);
            Bitmap grayScaleSegmentsImage = grayscaleFilter.Apply(overlayImage);

            alphaMatteFromColorFilter.ApplyInPlace(grayScaleSegmentsImage, overlayImage);
            
            // Color0
            ColorImages.Add(new BitmapUnsafe("Color0", colorImage));

            // Edges0
            workingImage = new BitmapUnsafe("Edges0", grayscaleFilter.Apply(cannyEdgeDetector.Apply(ColorImages[0].Bitmap)));
            compositeFilter.ApplyInPlace(workingImage.Bitmap, overlayImage);
            EdgesImages.Add(workingImage);

            // Color1
            ColorImages.Add(new BitmapUnsafe("Color1", gaussianBlur.Apply(ColorImages[0].Bitmap)));

            // Edges1
            workingImage = new BitmapUnsafe("Edges1", grayscaleFilter.Apply(cannyEdgeDetector.Apply(ColorImages[1].Bitmap)));
            compositeFilter.ApplyInPlace(workingImage.Bitmap, overlayImage);
            EdgesImages.Add(workingImage);

            // Color2
            ColorImages.Add(new BitmapUnsafe("Color2", gaussianBlur.Apply(ColorImages[1].Bitmap)));

            // Edges2
            workingImage = new BitmapUnsafe("Edges2", grayscaleFilter.Apply(cannyEdgeDetector.Apply(ColorImages[2].Bitmap)));
            compositeFilter.ApplyInPlace(workingImage.Bitmap, overlayImage);
            EdgesImages.Add(workingImage);

            // Color3
            ColorImages.Add(new BitmapUnsafe("Color3", gaussianBlur.Apply(ColorImages[2].Bitmap)));

            // Edges3
            workingImage = new BitmapUnsafe("Edges3", grayscaleFilter.Apply(cannyEdgeDetector.Apply(ColorImages[2].Bitmap)));
            compositeFilter.ApplyInPlace(workingImage.Bitmap, overlayImage);
            EdgesImages.Add(workingImage);

            // Color4
            ColorImages.Add(new BitmapUnsafe("Color4", gaussianBlur.Apply(ColorImages[3].Bitmap)));

            // Edges4
            workingImage = new BitmapUnsafe("Edges4", grayscaleFilter.Apply(cannyEdgeDetector.Apply(ColorImages[3].Bitmap)));
            compositeFilter.ApplyInPlace(workingImage.Bitmap, overlayImage);
            EdgesImages.Add(workingImage);
        }

        ~Tier()
        {
            foreach (BitmapUnsafe image in ColorImages)
            {
                image.Dispose();
            }
            foreach (BitmapUnsafe image in EdgesImages)
            {
                image.Dispose();
            }
        }

        public void Dispose()
        {
            foreach (BitmapUnsafe image in ColorImages)
            {
                image.Dispose();
            }
            foreach (BitmapUnsafe image in EdgesImages)
            {
                image.Dispose();
            }
            GC.SuppressFinalize(this);
        }        
    }
}
